package com.kh.rationaldrugreview.service;

import com.kh.rationaldrugreview.dto.EntityMatchResult;
import com.kh.rationaldrugreview.entity.EntityAlias;
import com.kh.rationaldrugreview.entity.KnowledgeEntity;
import com.kh.rationaldrugreview.mapper.KnowledgeEntityMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 实体匹配服务（传统算法层）
 * 实现多种匹配算法，不依赖LLM
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EntityMatchingService {
    
    private final KnowledgeEntityService knowledgeEntityService;
    private final KnowledgeEntityMapper knowledgeEntityMapper;
    
    // 剂型后缀列表
    private static final Set<String> DOSAGE_FORMS = Set.of(
        "片", "胶囊", "颗粒", "注射液", "口服液", "滴丸", "软膏", "乳膏", 
        "栓剂", "贴剂", "滴眼液", "滴鼻液", "喷雾剂", "混悬液", "溶液",
        "tablets", "capsules", "injection", "solution", "cream", "ointment"
    );
    
    // 常见缩写映射
    private static final Map<String, String> ABBREVIATIONS = Map.of(
        "VitC", "维生素C",
        "VitB", "维生素B",
        "VitD", "维生素D",
        "VitE", "维生素E",
        "VitK", "维生素K",
        "ASA", "阿司匹林",
        "PPI", "质子泵抑制剂"
    );
    
    /**
     * 执行多策略实体匹配
     */
    public EntityMatchResult matchEntity(String inputName, String entityType) {
        long startTime = System.currentTimeMillis();
        
        if (inputName == null || inputName.trim().isEmpty()) {
            return EntityMatchResult.notFound(inputName, entityType);
        }
        
        String trimmedInput = inputName.trim();
        List<EntityMatchResult.CandidateEntity> allCandidates = new ArrayList<>();
        EntityMatchResult.MatchDetails details = EntityMatchResult.MatchDetails.builder()
            .similarityScores(new HashMap<>())
            .matchingSteps(new ArrayList<>())
            .appliedRules(new ArrayList<>())
            .build();
        
        // 1. 精确匹配
        EntityMatchResult exactResult = performExactMatch(trimmedInput, entityType);
        if (exactResult.isMatched() && exactResult.getConfidence() >= 1.0) {
            exactResult.setProcessingTimeMs(System.currentTimeMillis() - startTime);
            log.debug("Exact match found for '{}': {}", inputName, exactResult.getCanonicalName());
            return exactResult;
        }
        details.getMatchingSteps().add("精确匹配未找到");
        
        // 2. 标准化匹配
        EntityMatchResult normalizedResult = performNormalizedMatch(trimmedInput, entityType, details);
        if (normalizedResult.isMatched() && normalizedResult.getConfidence() >= 0.9) {
            normalizedResult.setProcessingTimeMs(System.currentTimeMillis() - startTime);
            normalizedResult.setDetails(details);
            log.debug("Normalized match found for '{}': {}", inputName, normalizedResult.getCanonicalName());
            return normalizedResult;
        }
        if (normalizedResult.isMatched()) {
            allCandidates.add(createCandidate(normalizedResult.getMatchedEntity(), 
                normalizedResult.getConfidence(), "标准化匹配"));
        }
        
        // 3. 别名匹配
        EntityMatchResult aliasResult = performAliasMatch(trimmedInput, entityType);
        if (aliasResult.isMatched() && aliasResult.getConfidence() >= 0.85) {
            aliasResult.setProcessingTimeMs(System.currentTimeMillis() - startTime);
            aliasResult.setDetails(details);
            log.debug("Alias match found for '{}': {}", inputName, aliasResult.getCanonicalName());
            return aliasResult;
        }
        if (aliasResult.isMatched()) {
            allCandidates.add(createCandidate(aliasResult.getMatchedEntity(), 
                aliasResult.getConfidence(), "别名匹配"));
        }
        
        // 4. 缩写匹配
        EntityMatchResult abbreviationResult = performAbbreviationMatch(trimmedInput, entityType);
        if (abbreviationResult.isMatched()) {
            if (abbreviationResult.getConfidence() >= 0.85) {
                abbreviationResult.setProcessingTimeMs(System.currentTimeMillis() - startTime);
                abbreviationResult.setDetails(details);
                return abbreviationResult;
            }
            allCandidates.add(createCandidate(abbreviationResult.getMatchedEntity(), 
                abbreviationResult.getConfidence(), "缩写匹配"));
        }
        
        // 5. 模糊匹配（编辑距离）
        List<EntityMatchResult.CandidateEntity> fuzzyCandidates = 
            performFuzzyMatch(trimmedInput, entityType, details);
        allCandidates.addAll(fuzzyCandidates);
        
        // 6. 部分匹配
        List<EntityMatchResult.CandidateEntity> partialCandidates = 
            performPartialMatch(trimmedInput, entityType);
        allCandidates.addAll(partialCandidates);
        
        // 选择最佳候选
        if (!allCandidates.isEmpty()) {
            // 按相似度排序
            allCandidates.sort((c1, c2) -> Double.compare(c2.getSimilarity(), c1.getSimilarity()));
            
            EntityMatchResult.CandidateEntity bestCandidate = allCandidates.get(0);
            KnowledgeEntity bestEntity = knowledgeEntityMapper.findById(bestCandidate.getEntityId());
            
            if (bestEntity != null && bestCandidate.getSimilarity() >= 0.7) {
                details.getMatchingSteps().add("选择最佳候选：" + bestCandidate.getEntityName());
                
                return EntityMatchResult.builder()
                    .originalName(inputName)
                    .matchedEntity(bestEntity)
                    .canonicalName(bestEntity.getCanonicalName())
                    .entityId(bestEntity.getEntityId())
                    .entityType(entityType)
                    .matchType(EntityMatchResult.MatchType.FUZZY)
                    .algorithm(EntityMatchResult.MatchAlgorithm.HYBRID)
                    .confidence(bestCandidate.getSimilarity())
                    .candidates(allCandidates.size() > 1 ? allCandidates.subList(0, Math.min(5, allCandidates.size())) : null)
                    .needsConfirmation(bestCandidate.getSimilarity() < 0.85)
                    .details(details)
                    .processingTimeMs(System.currentTimeMillis() - startTime)
                    .matchedAt(LocalDateTime.now())
                    .build();
            }
        }
        
        // 未找到匹配
        EntityMatchResult notFoundResult = EntityMatchResult.notFound(inputName, entityType);
        notFoundResult.setCandidates(allCandidates.isEmpty() ? null : 
            allCandidates.subList(0, Math.min(5, allCandidates.size())));
        notFoundResult.setDetails(details);
        notFoundResult.setProcessingTimeMs(System.currentTimeMillis() - startTime);
        
        return notFoundResult;
    }
    
    /**
     * 精确匹配
     */
    private EntityMatchResult performExactMatch(String inputName, String entityType) {
        KnowledgeEntity entity = knowledgeEntityService.findEntity(entityType, inputName);
        if (entity != null) {
            return EntityMatchResult.exactMatch(inputName, entity);
        }
        return EntityMatchResult.notFound(inputName, entityType);
    }
    
    /**
     * 标准化匹配
     */
    private EntityMatchResult performNormalizedMatch(String inputName, String entityType, 
                                                    EntityMatchResult.MatchDetails details) {
        EntityMatchResult.NormalizationProcess process = EntityMatchResult.NormalizationProcess.builder()
            .originalInput(inputName)
            .removedParts(new ArrayList<>())
            .build();
        
        String normalized = inputName;
        
        // 去除首尾空格
        normalized = normalized.trim();
        process.setAfterTrim(normalized);
        
        // 统一大小写
        String lowerCase = normalized.toLowerCase();
        process.setAfterCaseConversion(lowerCase);
        
        // 去除标点符号
        String noPunctuation = normalized.replaceAll("[，。、；：！？（）\\[\\]{}\"']", "");
        process.setAfterPunctuationRemoval(noPunctuation);
        
        // 去除剂型后缀
        String noDosageForm = removeDosageForm(normalized);
        if (!noDosageForm.equals(normalized)) {
            process.getRemovedParts().add(normalized.substring(noDosageForm.length()));
        }
        process.setAfterDosageFormRemoval(noDosageForm);
        
        // 统一括号格式
        String finalNormalized = noDosageForm
            .replaceAll("（", "(")
            .replaceAll("）", ")")
            .replaceAll("\\s+", " ");
        process.setFinalNormalized(finalNormalized);
        
        if (details != null && details.getNormalization() == null) {
            details.setNormalization(process);
        }
        
        // 尝试匹配标准化后的名称
        KnowledgeEntity entity = knowledgeEntityService.findEntity(entityType, finalNormalized);
        if (entity != null) {
            return EntityMatchResult.builder()
                .originalName(inputName)
                .matchedEntity(entity)
                .canonicalName(entity.getCanonicalName())
                .entityId(entity.getEntityId())
                .entityType(entityType)
                .matchType(EntityMatchResult.MatchType.NORMALIZED)
                .algorithm(EntityMatchResult.MatchAlgorithm.NORMALIZATION)
                .confidence(0.95)
                .needsConfirmation(false)
                .matchedAt(LocalDateTime.now())
                .build();
        }
        
        return EntityMatchResult.notFound(inputName, entityType);
    }
    
    /**
     * 别名匹配
     */
    private EntityMatchResult performAliasMatch(String inputName, String entityType) {
        KnowledgeEntity entity = knowledgeEntityMapper.findByAlias(inputName);
        if (entity != null && entity.getEntityType().equals(entityType)) {
            return EntityMatchResult.builder()
                .originalName(inputName)
                .matchedEntity(entity)
                .canonicalName(entity.getCanonicalName())
                .entityId(entity.getEntityId())
                .entityType(entityType)
                .matchType(EntityMatchResult.MatchType.ALIAS)
                .algorithm(EntityMatchResult.MatchAlgorithm.ALIAS_LOOKUP)
                .confidence(0.9)
                .needsConfirmation(false)
                .matchedAt(LocalDateTime.now())
                .build();
        }
        return EntityMatchResult.notFound(inputName, entityType);
    }
    
    /**
     * 缩写匹配
     */
    private EntityMatchResult performAbbreviationMatch(String inputName, String entityType) {
        // 检查是否为已知缩写
        String expanded = ABBREVIATIONS.get(inputName);
        if (expanded != null) {
            return performExactMatch(expanded, entityType);
        }
        
        // 检查是否包含缩写
        for (Map.Entry<String, String> entry : ABBREVIATIONS.entrySet()) {
            if (inputName.contains(entry.getKey())) {
                String replaced = inputName.replace(entry.getKey(), entry.getValue());
                EntityMatchResult result = performExactMatch(replaced, entityType);
                if (result.isMatched()) {
                    result.setConfidence(0.85); // 稍微降低置信度
                    return result;
                }
            }
        }
        
        return EntityMatchResult.notFound(inputName, entityType);
    }
    
    /**
     * 模糊匹配（基于编辑距离）
     */
    private List<EntityMatchResult.CandidateEntity> performFuzzyMatch(String inputName, 
                                                                      String entityType, 
                                                                      EntityMatchResult.MatchDetails details) {
        List<EntityMatchResult.CandidateEntity> candidates = new ArrayList<>();
        List<KnowledgeEntity> allEntities = knowledgeEntityMapper.findByType(entityType);
        
        for (KnowledgeEntity entity : allEntities) {
            // 计算编辑距离
            int distance = calculateLevenshteinDistance(inputName.toLowerCase(), 
                entity.getEntityName().toLowerCase());
            
            // 计算相似度（基于编辑距离）
            double similarity = 1.0 - (double) distance / Math.max(inputName.length(), entity.getEntityName().length());
            
            if (similarity >= 0.7) {
                candidates.add(createCandidate(entity, similarity, "编辑距离匹配"));
                
                if (details != null) {
                    details.getSimilarityScores().put(entity.getEntityName(), similarity);
                }
            }
        }
        
        if (details != null) {
            details.getAppliedRules().add("Levenshtein距离算法");
        }
        
        return candidates;
    }
    
    /**
     * 部分匹配
     */
    private List<EntityMatchResult.CandidateEntity> performPartialMatch(String inputName, String entityType) {
        List<EntityMatchResult.CandidateEntity> candidates = new ArrayList<>();
        List<KnowledgeEntity> allEntities = knowledgeEntityMapper.findByType(entityType);
        
        String lowerInput = inputName.toLowerCase();
        
        for (KnowledgeEntity entity : allEntities) {
            String lowerEntityName = entity.getEntityName().toLowerCase();
            
            // 检查是否包含
            if (lowerEntityName.contains(lowerInput) || lowerInput.contains(lowerEntityName)) {
                double similarity = (double) Math.min(inputName.length(), entity.getEntityName().length()) 
                    / Math.max(inputName.length(), entity.getEntityName().length());
                
                if (similarity >= 0.5) {
                    candidates.add(createCandidate(entity, similarity * 0.8, "部分匹配"));
                }
            }
        }
        
        return candidates;
    }
    
    /**
     * 去除剂型后缀
     */
    private String removeDosageForm(String name) {
        for (String form : DOSAGE_FORMS) {
            if (name.endsWith(form)) {
                return name.substring(0, name.length() - form.length()).trim();
            }
        }
        return name;
    }
    
    /**
     * 计算Levenshtein编辑距离
     */
    private int calculateLevenshteinDistance(String s1, String s2) {
        int[][] dp = new int[s1.length() + 1][s2.length() + 1];
        
        for (int i = 0; i <= s1.length(); i++) {
            dp[i][0] = i;
        }
        
        for (int j = 0; j <= s2.length(); j++) {
            dp[0][j] = j;
        }
        
        for (int i = 1; i <= s1.length(); i++) {
            for (int j = 1; j <= s2.length(); j++) {
                int cost = s1.charAt(i - 1) == s2.charAt(j - 1) ? 0 : 1;
                dp[i][j] = Math.min(Math.min(
                    dp[i - 1][j] + 1,      // 删除
                    dp[i][j - 1] + 1),     // 插入
                    dp[i - 1][j - 1] + cost // 替换
                );
            }
        }
        
        return dp[s1.length()][s2.length()];
    }
    
    /**
     * 创建候选实体
     */
    private EntityMatchResult.CandidateEntity createCandidate(KnowledgeEntity entity, 
                                                             double similarity, 
                                                             String matchReason) {
        return EntityMatchResult.CandidateEntity.builder()
            .entityId(entity.getEntityId())
            .entityName(entity.getEntityName())
            .canonicalName(entity.getCanonicalName())
            .entityType(entity.getEntityType())
            .similarity(similarity)
            .matchReason(matchReason)
            .attributes(entity.getAttributes())
            .build();
    }
    
    /**
     * 批量匹配实体
     */
    public List<EntityMatchResult> batchMatch(List<String> inputNames, String entityType) {
        return inputNames.stream()
            .map(name -> matchEntity(name, entityType))
            .collect(Collectors.toList());
    }
}